/**
 * Created by 61703 on 2018/10/16.
 */
/**
 *   Unslider
 *   version 2.0
 *   by @idiot and friends
 *
 *   modified by xuyingjun@zcool.com.cn
 *    1.修改插入标签的格式，以兼容jq1.X
 *    2.修改calculateSlides函数。
 *    3.修改百分比为px
 *    4.animate增加speed参数
 *    5,添加resize事件，更新slide尺寸。
 */
(function ($) {
    //  Don't throw any errors when jQuery
    if (!$) {
        return console.warn('Unslider needs jQuery');
    }

    $.Unslider = function (context, options) {
        var self = this;

        //  Create an Unslider reference we can use everywhere
        self._ = 'unslider';

        //  Store our default options in here
        //  Everything will be overwritten by the jQuery plugin though
        self.defaults = {
            //  Should the slider move on its own or only when
            //  you interact with the nav/arrows?
            //  Only accepts boolean true/false.
            autoplay: false,

            // 是否在鼠标悬浮时暂停。
            // 默认是
            hoverToStop: true,

            //  3 second delay between slides moving, pass
            //  as a number in milliseconds.
            delay: 3000,

            //  Animation speed in millseconds
            speed: 750,

            //  An easing string to use. If you're using Velocity, use a
            //  Velocity string otherwise you can use jQuery/jQ UI options.
            easing: 'swing', // [.42, 0, .58, 1],

            //  Does it support keyboard arrows?
            //  Can pass either true or false -
            //  or an object with the keycodes, like so:
            //  {
            //	 prev: 37,
            //	 next: 39
            // }
            //  You can call any internal method name
            //  before the keycode and it'll be called.
            keys: {
                prev: 37,
                next: 39
            },

            //  Do you want to generate clickable navigation
            //  to skip to each slide? Accepts boolean true/false or
            //  a callback function per item to generate.
            nav: false,

            //  Should there be left/right arrows to go back/forth?
            //   -> This isn't keyboard support.
            //  Either set true/false, or an object with the HTML
            //  elements for each arrow like below:
            arrows: {
                prev: '<a href="javascript:;" class="' + self._ + '-arrow prev">上一张</a>',
                next: '<a href="javascript:;" class="' + self._ + '-arrow next">下一张</a>'
            },

            //  How should Unslider animate?
            //  It can do one of the following types:
            //  "fade": each slide fades in to each other
            //  "horizontal": each slide moves from left to right
            //  "vertical": each slide moves from top to bottom
            animation: 'horizontal',

            //  If you don't want to use a list to display your slides,
            //  you can change it here. Not recommended and you'll need
            //  to adjust the CSS accordingly.
            selectors: {
                container: 'ul:first',
                slides: 'li'
            },

            //  Do you want to animate the heights of each slide as
            //  it moves
            animateHeight: false,

            //  Active class for the nav
            activeClass: self._ + '-active',

            //  Have swipe support?
            //  You can set this here with a boolean and always use
            //  initSwipe/destroySwipe later on.
            swipe: true
        };

        //  Set defaults
        self.$context = context;
        self.options = {};

        //  Leave our elements blank for now
        //  Since they get changed by the options, we'll need to
        //  set them in the init method.
        self.$parent = null;
        self.$container = null;
        self.$slides = null;
        self.$nav = null;
        self.$arrows = [];

        //  Set our indexes and totals
        self.total = 0;
        self.current = 0;

        //  Generate a specific random ID so we don't dupe events
        self.prefix = self._ + '-';
        self.eventSuffix = '.' + self.prefix + ~~(Math.random() * 2e3);

        //  In case we're going to use the autoplay
        self.interval = null;

        //  Get everything set up innit
        self.init = function (options) {
            //  Set up our options inside here so we can re-init at
            //  any time
            self.options = $.extend({}, self.defaults, options);

            //  Our elements
            self.$container = self.$context.find(self.options.selectors.container).addClass(self.prefix + 'wrap');
            self.$slides = self.$container.children(self.options.selectors.slides);

            //  We'll manually init the container
            self.setup();

            //  We want to keep this script as small as possible
            //  so we'll optimise some checks
            $.each(['nav', 'arrows', 'keys', 'infinite'], function (index, module) {
                self.options[module] && self['init' + $._ucfirst(module)]();
            });

            //  Add swipe support
            if (jQuery.event.special.swipe && self.options.swipe) {
                self.initSwipe();
            }

            //  If autoplay is set to true, call self.start()
            //  to start calling our timeouts
            self.options.autoplay && self.start();

            //自动播放，且悬浮暂停，则初始化
            self.options.autoplay && self.options.hoverToStop && self.initHoverEvent();

            //  We should be able to recalculate slides at will
            self.calculateSlides();
            self.initResizeEvent();

            //  Listen to a ready event
            self.$context.trigger(self._ + '.ready');

            //  Everyday I'm chainin'
            return self.animate(self.options.index || self.current, 'init');
        };
        self.initResizeEvent = function () {
            $(window).on('resize', function (e) {
                self.calculateSlides();
            })
        };

        self.setup = function () {
            //  Add a CSS hook to the main element
            self.$context.addClass(self.prefix + self.options.animation).wrap('<div class="' + self._ + '" ></div>');
            self.$parent = self.$context.parent('.' + self._);

            //  We need to manually check if the container is absolutely
            //  or relatively positioned
            var position = self.$context.css('position');

            //  If we don't already have a position set, we'll
            //  automatically set it ourselves
            if (position === 'static') {
                self.$context.css('position', 'relative');
            }

            self.$context.css('overflow', 'hidden');
        };

        //  Set up the slide widths to animate with
        //  so the box doesn't float over
        self.calculateSlides = function () {
            self.$slides = self.$container.children(self.options.selectors.slides);
            self.total = self.$slides.length;

            //  Set the total width
            if (self.options.animation !== 'fade') {
                var prop = 'width';

                if (self.options.animation === 'vertical') {
                    prop = 'height';
                }

                var width = self.$container.parent().css(prop).split("px")[0];
                self.$container.css(prop, (self.total * width) + 'px').addClass(self.prefix + 'carousel');
                self.$slides.css(prop, (width) + 'px');
            }
        };


        //  Start our autoplay
        self.start = function () {
            //不要被此处的interval所迷惑, 其实是timeout!!
            //这个地方和animate里面的stop().start()相呼应
            //估计是后来改的 但是没有重新梳理，精简。
            self.interval = setTimeout(function () {
                //  Move on to the next slide
                // if mouse is not hovering
                if (!self.isHover) {
                    self.next();
                } else {
                    self.start();
                }

                //  If we've got autoplay set up
                //  we don't need to keep starting
                //  the slider from within our timeout
                //  as .animate() calls it for us
            }, self.options.delay);

            return self;
        };

        //  And pause our timeouts
        //  and force stop the slider if needed
        self.stop = function () {
            clearTimeout(self.interval);

            return self;
        };

        // 悬浮暂停动画。
        // 改为变量拦截，而非直接stop()。为了避免临时鼠标经过而导致的计时器重置。
        self.initHoverEvent = function () {
            self.$container.hover(function () {
                //self.stop();
                self.isHover = true;
            }, function () {
                self.isHover = false;
                //if (self.options.autoplay)
                //    self.start();
            })
        }
        //  Set up our navigation
        self.initNav = function () {
            var $nav = $('<nav class="' + self.prefix + 'nav"><ol></ol></nav>');

            //  Build our click navigation item-by-item
            self.$slides.each(function (key) {
                //  If we've already set a label, let's use that
                //  instead of generating one
                var label = this.getAttribute('data-nav') || key + 1;

                //  Listen to any callback functions
                if ($.isFunction(self.options.nav)) {
                    label = self.options.nav.call(self.$slides.eq(key), key, label);
                }

                //  And add it to our navigation item
                $nav.children('ol').append('<li data-slide="' + key + '">' + label + '</li>');
            });

            //  Keep a copy of the nav everywhere so we can use it
            self.$nav = $nav.insertAfter(self.$context);

            //  Now our nav is built, let's add it to the slider and bind
            //  for any click events on the generated links
            self.$nav.find('li').on('click' + self.eventSuffix, function () {
                //  Cache our link and set it to be active
                var $me = $(this).addClass(self.options.activeClass);

                //  Set the right active class, remove any other ones
                $me.siblings().removeClass(self.options.activeClass);

                //  Move the slide
                self.animate($me.attr('data-slide'));
            });
            //计算并设置ol的宽度
            var lis = self.$nav.find('li');
            self.$nav.children('ol').css({
                width: lis.length * lis.outerWidth(true)
            })
        };


        //  Set up our left-right arrow navigation
        //  (Not keyboard arrows, prev/next buttons)
        self.initArrows = function () {
            if (self.options.arrows === true) {
                self.options.arrows = self.defaults.arrows;
            }

            //  Loop our options object and bind our events
            $.each(self.options.arrows, function (key, val) {
                //  Add our arrow HTML and bind it
                self.$arrows.push(
                    $(val).insertAfter(self.$context).on('click' + self.eventSuffix, self[key])
                );
            });
        };


        //  Set up our keyboad navigation
        //  Allow binding to multiple keycodes
        self.initKeys = function () {
            if (self.options.keys === true) {
                self.options.keys = self.defaults.keys;
            }

            $(document).on('keyup' + self.eventSuffix, function (e) {
                $.each(self.options.keys, function (key, val) {
                    if (e.which === val) {
                        $.isFunction(self[key]) && self[key].call(self);
                    }
                });
            });
        };

        //  Requires jQuery.event.swipe
        //  -> stephband.info/jquery.event.swipe
        self.initSwipe = function () {
            var width = self.$slides.width();

            self.$container.on({
                swipeleft: self.next,
                swiperight: self.prev,

                movestart: function (e) {
                    //  If the movestart heads off in a upwards or downwards
                    //  direction, prevent it so that the browser scrolls normally.
                    if ((e.distX > e.distY && e.distX < -e.distY) || (e.distX < e.distY && e.distX > -e.distY)) {
                        return !!e.preventDefault();
                    }

                    self.$container.css('position', 'relative');
                }
            });

            //  We don't want to have a tactile swipe in the slider
            //  in the fade animation, as it can cause some problems
            //  with layout, so we'll just disable it.
            if (self.options.animation !== 'fade') {
                self.$container.on({
                    move: function (e) {
                        self.$container.css('left', -(100 * self.current) + (100 * e.distX / width) + '%');
                    },

                    moveend: function (e) {
                        if ((Math.abs(e.distX) / width) < $.event.special.swipe.settings.threshold) {
                            return self._move(self.$container, {left: -(100 * self.current) + '%'}, false, 200);
                        }
                    }
                });
            }
        };

        //  Infinite scrolling is a massive pain in the arse
        //  so we need to create a whole bloody function to set
        //  it up. Argh.
        self.initInfinite = function () {
            var pos = ['first', 'last'];

            $.each(pos, function (index, item) {
                self.$slides.push.apply(
                    self.$slides,

                    //  Exclude all cloned slides and call .first() or .last()
                    //  depending on what `item` is.
                    self.$slides.filter(':not(".' + self._ + '-clone")')[item]()

                    //  Make a copy of it and identify it as a clone
                        .clone().addClass(self._ + '-clone')

                        //  Either insert before or after depending on whether we're
                        //  the first or last clone
                        ['insert' + (index === 0 ? 'After' : 'Before')](
                        //  Return the other element in the position array
                        //  if item = first, return "last"
                        self.$slides[pos[~~!index]]()
                    )
                );
            });
        };

        //  Remove any trace of arrows
        //  Loop our array of arrows and use jQuery to remove
        //  It'll unbind any event handlers for us
        self.destroyArrows = function () {
            $.each(self.$arrows, function (i, $arrow) {
                $arrow.remove();
            });
        };

        //  Remove any swipe events and reset the position
        self.destroySwipe = function () {
            //  We bind to 4 events, so we'll unbind those
            self.$container.off('movestart move moveend');
        };

        //  Unset the keyboard navigation
        //  Remove the handler
        self.destroyKeys = function () {
            //  Remove the event handler
            $(document).off('keyup' + self.eventSuffix);
        };

        self.setIndex = function (to) {
            if (to < 0) {
                to = self.total - 1;
            }

            self.current = Math.min(Math.max(0, to), self.total - 1);

            if (self.options.nav) {
                self.$nav.find('[data-slide="' + self.current + '"]')._active(self.options.activeClass);
            }

            self.$slides.eq(self.current)._active(self.options.activeClass);

            return self;
        };

        //  Despite the name, this doesn't do any animation - since there's
        //  now three different types of animation, we let this method delegate
        //  to the right type, keeping the name for backwards compat.
        self.animate = function (to, speed) {
            //  Animation shortcuts
            //  Instead of passing a number index, we can now
            //  use .data('unslider').animate('last');
            //  or .unslider('animate:last')
            //  to go to the very last slide
            if (to === 'first') to = 0;
            if (to === 'last') to = self.total;

            //  Don't animate if it's not a valid index
            if (isNaN(to)) {
                return self;
            }
            //若非数字，则设定为默认值。
            if (isNaN(+speed)) {
                speed = self.options.speed;
            }

            if (self.options.autoplay) {
                self.stop().start();
            }

            self.setIndex(to);

            //  Add a callback method to do stuff with
            self.$context.trigger(self._ + '.change', [to, self.$slides.eq(to)]);

            //  Delegate the right method - everything's named consistently
            //  so we can assume it'll be called "animate" +
            var fn = 'animate' + $._ucfirst(self.options.animation);

            //  Make sure it's a valid animation method, otherwise we'll get
            //  a load of bug reports that'll be really hard to report
            if ($.isFunction(self[fn])) {
                self[fn](self.current, speed);
            }

            return self;
        };


        //  Shortcuts for animating if we don't know what the current
        //  index is (i.e back/forward)
        //  For moving forward we need to make sure we don't overshoot.
        self.next = function () {
            var target = self.current + 1;

            //  If we're at the end, we need to move back to the start
            if (target >= self.total) {
                target = 0;
            }

            return self.animate(target, 'next');
        };

        //  Previous is a bit simpler, we can just decrease the index
        //  by one and check if it's over 0.
        self.prev = function () {
            return self.animate(self.current - 1, 'prev');
        };


        //  Our default animation method, the old-school left-to-right
        //  horizontal animation
        self.animateHorizontal = function (to, speed) {
            var prop = 'left';

            //  Add RTL support, slide the slider
            //  the other way if the site is right-to-left
            if (self.$context.attr('dir') === 'rtl') {
                prop = 'right';
            }

            if (self.options.infinite) {
                //  So then we need to hide the first slide
                self.$container.css('margin-' + prop, '-100%');
            }

            return self.slide(prop, to, speed);
        };

        //  The same animation methods, but vertical support
        //  RTL doesn't affect the vertical direction so we
        //  can just call as is
        self.animateVertical = function (to, speed) {
            self.options.animateHeight = true;

            //  Normal infinite CSS fix doesn't work for
            //  vertical animation so we need to manually set it
            //  with pixels. Ah well.
            if (self.options.infinite) {
                self.$container.css('margin-top', -self.$slides.outerHeight());
            }

            return self.slide('top', to, speed);
        };

        //  Actually move the slide now
        //  We have to pass a property to animate as there's
        //  a few different directions it can now move, but it's
        //  otherwise unchanged from before.
        self.slide = function (prop, to, speed) {
            //  If we want to change the height of the slider
            //  to match the current slide, you can set
            //  {animateHeight: true}
            if (self.options.animateHeight) {
                self._move(self.$context, {height: self.$slides.eq(to).outerHeight()}, false);
            }

            //  For infinite sliding we add a dummy slide at the end and start
            //  of each slider to give the appearance of being infinite
            if (self.options.infinite) {
                var dummy;

                //  Going backwards to last slide
                if (to === self.total - 1) {
                    //  We're setting a dummy position and an actual one
                    //  the dummy is what the index looks like
                    //  (and what we'll silently update to afterwards),
                    //  and the actual is what makes it not go backwards
                    dummy = self.total - 3;
                    to = -1;
                }

                //  Going forwards to first slide
                if (to === self.total - 2) {
                    dummy = 0;
                    to = self.total - 2;
                }

                //  If it's a number we can safely set it
                if (typeof dummy === 'number') {
                    self.setIndex(dummy);

                    //  Listen for when the slide's finished transitioning so
                    //  we can silently move it into the right place and clear
                    //  this whole mess up.
                    self.$context.on(self._ + '.moved', function () {
                        if (self.current === dummy) {
                            self.$container.css(prop, -(100 * dummy) + '%').off(self._ + '.moved');
                        }
                    });
                }
            }

            //  We need to create an object to store our property in
            //  since we don't know what it'll be.
            var obj = {};

            //  Manually create it here
            obj[prop] = -(100 * to) + '%';

            //  And animate using our newly-created object
            return self._move(self.$container, obj, null, speed);
        };


        //  Fade between slides rather than, uh, sliding it
        self.animateFade = function (to) {
            var $active = self.$slides.eq(to).addClass(self.options.activeClass);

            //  Toggle our classes
            self._move($active.siblings().removeClass(self.options.activeClass), {opacity: 0});
            self._move($active, {opacity: 1}, false);
        };

        self._move = function ($el, obj, callback, speed) {
            if (callback !== false) {
                callback = function () {
                    self.$context.trigger(self._ + '.moved');
                };
            }
            speed = typeof speed === "undefined" ? self.options.speed : +speed;
            return $el._move(obj, speed, self.options.easing, callback);
        };

        //  Allow daisy-chaining of methods
        return self.init(options);
    };

    //  Internal (but global) jQuery methods
    //  They're both just helpful types of shorthand for
    //  anything that might take too long to write out or
    //  something that might be used more than once.
    $.fn._active = function (className) {
        return this.addClass(className).siblings().removeClass(className);
    };

    //  The equivalent to PHP's ucfirst(). Take the first
    //  character of a string and make it uppercase.
    //  Simples.
    $._ucfirst = function (str) {
        //  Take our variable, run a regex on the first letter
        return (str + '').toLowerCase().replace(/^./, function (match) {
            //  And uppercase it. Simples.
            return match.toUpperCase();
        });
    };

    $.fn._move = function () {
        this.stop(true, true);
        return $.fn[$.fn.velocity ? 'velocity' : 'animate'].apply(this, arguments);
    };

    //  And set up our jQuery plugin
    $.fn.unslider = function (opts) {
        return this.each(function () {
            var $this = $(this);

            //  Allow usage of .unslider('function_name')
            //  as well as using .data('unslider') to access the
            //  main Unslider object
            if (typeof opts === 'string' && $this.data('unslider')) {
                opts = opts.split(':');

                var call = $this.data('unslider')[opts[0]];

                //  Do we have arguments to pass to the string-function?
                if ($.isFunction(call)) {
                    return call.apply($this, opts[1] ? opts[1].split(',') : null);
                }
            }

            return $this.data('unslider', new $.Unslider($this, opts));
        });
    };

})(window.jQuery);